import 'package:flutter/material.dart';

void main() {
  runApp(const CustomMapKeyDemoApp());
}

class CustomMapKeyDemoApp extends StatelessWidget {
  const CustomMapKeyDemoApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Dart 自定义 Map 键演示',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: const CustomMapKeyDemoScreen(),
    );
  }
}

class CustomMapKeyDemoScreen extends StatefulWidget {
  const CustomMapKeyDemoScreen({super.key});

  @override
  State<CustomMapKeyDemoScreen> createState() => _CustomMapKeyDemoScreenState();
}

class _CustomMapKeyDemoScreenState extends State<CustomMapKeyDemoScreen> {
  String _output = '';
  final ScrollController _scrollController = ScrollController();

  // 运行演示
  void _runDemo() {
    _clearOutput();

    // 创建自定义类实例作为 Map 键
    final alice = Person('Alice', 30);
    final bob = Person('Bob', 25);
    final aliceCopy = Person('Alice', 30); // 与 alice 内容相同

    // 使用自定义类作为键的 Map
    final map = <Person, String>{alice: '用户1', bob: '用户2'};

    _log('原始 Map 内容:');
    map.forEach((key, value) => _log('${key.name}: ${value}'));

    // 测试相等性和哈希码
    _log('\n对象相等性测试:');
    _log('alice == aliceCopy: ${alice == aliceCopy}');
    _log(
      'alice.hashCode == aliceCopy.hashCode: ${alice.hashCode == aliceCopy.hashCode}',
    );

    // 使用相同内容的实例访问 Map
    _log('\n通过 aliceCopy 访问 Map: ${map[aliceCopy]}');

    // 演示 Map 唯一性
    _log('\n添加 aliceCopy 到 Map:');
    map[aliceCopy] = '用户1（副本）';
    _log('Map 大小: ${map.length}'); // 应保持为2，因为键已存在
    map.forEach((key, value) => _log('${key.name}: ${value}'));
  }

  // 添加自定义用户到 Map
  void _addCustomUser() {
    _clearOutput();

    // 生成随机用户
    final user1 = Person('张三', 28);
    final user2 = Person('李四', 35);
    final user1Copy = Person('张三', 28); // 与 user1 内容相同

    // 使用自定义类作为键的 Map
    final map = <Person, String>{};
    map[user1] = '员工1';
    map[user2] = '员工2';

    _log('添加自定义用户到 Map:');
    map.forEach((key, value) => _log('${key.name}: ${value}'));

    // 测试通过副本访问
    _log('\n通过 user1Copy 访问 Map: ${map[user1Copy]}');

    // 演示更新值
    _log('\n更新 user1 的值:');
    map[user1Copy] = '经理'; // 实际上是更新 user1 的值
    map.forEach((key, value) => _log('${key.name}: ${value}'));
  }

  // 辅助方法
  void _log(String message) {
    setState(() {
      _output += '$message\n';
      _scrollController.animateTo(
        _scrollController.position.maxScrollExtent,
        duration: const Duration(milliseconds: 300),
        curve: Curves.easeOut,
      );
    });
  }

  void _clearOutput() {
    setState(() {
      _output = '';
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Dart 自定义 Map 键演示'), centerTitle: true),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // 控制按钮
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                ElevatedButton(onPressed: _runDemo, child: const Text('基础演示')),
                ElevatedButton(
                  onPressed: _addCustomUser,
                  child: const Text('自定义用户演示'),
                ),
              ],
            ),

            const SizedBox(height: 16),

            // 输出区域
            Expanded(
              child: Container(
                decoration: BoxDecoration(
                  border: Border.all(color: Colors.grey.shade300),
                  borderRadius: BorderRadius.circular(8),
                  color: Colors.grey.shade50,
                ),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: [
                    Container(
                      padding: const EdgeInsets.all(8),
                      color: Colors.grey.shade200,
                      child: const Text(
                        '演示结果',
                        style: TextStyle(fontWeight: FontWeight.bold),
                      ),
                    ),
                    Expanded(
                      child: SingleChildScrollView(
                        controller: _scrollController,
                        padding: const EdgeInsets.all(12),
                        child: SelectableText(
                          _output.isEmpty ? '点击按钮运行演示...' : _output,
                          style: const TextStyle(
                            fontFamily: 'monospace',
                            fontSize: 14,
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),

            const SizedBox(height: 16),

            // 说明文本
            Container(
              padding: const EdgeInsets.all(12),
              decoration: BoxDecoration(
                color: Colors.blue.shade50,
                borderRadius: BorderRadius.circular(8),
              ),
              child: const Text(
                '自定义 Map 键说明:\n'
                '1. 必须重写 hashCode 和 operator == 方法\n'
                '2. 相等的对象必须产生相同的哈希码\n'
                '3. Map 根据哈希码和相等性判断键是否存在\n'
                '4. 推荐使用 Object.hash() 生成哈希码',
                style: TextStyle(fontSize: 14),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class Person {
  final String name;
  final int age;

  Person(this.name, this.age);

  // 重写 == 方法判断对象相等性
  @override
  bool operator ==(Object other) {
    if (other.runtimeType != runtimeType) return false;
    return other is Person && other.name == name && other.age == age;
  }

  // 重写 hashCode 方法生成唯一哈希码
  @override
  int get hashCode => Object.hash(name, age);

  @override
  String toString() => '$name (年龄: $age)';
}
